package com.woniu.web.aop;

import cn.hutool.json.JSONUtil;
import com.woniu.web.annotation.LogInfo;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

@Component
@Aspect
@Slf4j
public class LogAop {
    //日志是从开始到结束都应该要记录，所以使用环绕通知
    //切入点可以是方法，也可以是注解
    @Around("@annotation(com.woniu.web.annotation.LogInfo)")
    //在 Spring AOP（面向切面编程）中，ProceedingJoinPoint 是一个接口，代表了可以被拦截的连接点，通常用于环绕通知（Around Advice）中。它包含了当前被拦截的方法的信息，允许在方法执行前后进行操作。
    //
    //具体来说，ProceedingJoinPoint 接口提供了以下方法：
    //
    //proceed()：这个方法用于显式地调用被通知的方法。在环绕通知中，
    // 当需要继续目标方法的执行时，就会调用 proceed() 方法，从而触发目标方法的执行。
    //
    //getArgs()：获取被通知方法的参数列表。
    //
    //getTarget()：获取被通知的目标对象。
    //
    //getSignature()：获取被通知方法的签名信息，比如方法名、返回类型等。
    //
    //其他方法：还有一些其他方法可以获取连接点的上下文信息，例如获取代理对象等。
    //
    //在编写环绕通知时，你可以将 ProceedingJoinPoint 作为环绕通知方法的参数，
    // 通过调用它的 proceed() 方法来控制目标方法的执行以及在方法执行前后进行一些操作。
    public Object log(ProceedingJoinPoint pjp) throws Throwable{
        //1.获取切入点方法
        MethodSignature ms = (MethodSignature) pjp.getSignature();
        //获得方法上的注解
        LogInfo li = ms.getMethod().getDeclaredAnnotation(LogInfo.class);
        //2.日志信息构建
        String info = "======开始执行" +li.value()+"业务{}==========";
        //3.输出开始的日志
        if(li.param()) log.info(info.toString(),"参数是"+ JSONUtil.parse(pjp.getArgs()).toString());
        else log.info(info,"");
        Long start=System.currentTimeMillis();
        Object obj = pjp.proceed();
        //4.构建结束日志
        info ="==="+li.value()+"结束执行，结果是:{}{}" ;
        if(li.time()) log.info(info.toString(),JSONUtil.parse(obj).toString(),",耗时+"+(System.currentTimeMillis()-start));
        else log.info(info.toString(),"参数是"+ JSONUtil.parse(obj).toString());
        return obj;
    }

}
